package com.ophiux.pay.controller.notify;

import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.ophiux.pay.config.WechatPayV3Properties;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.partnerpayments.jsapi.model.Transaction;
import com.wechat.pay.java.service.refund.model.RefundNotification;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @desc: 微信支付回调通知
 * @author: hhl
 * @date：2023/2/13 14:41
 */
@Controller
@RequestMapping("/wechat/notify")
@Slf4j
public class WechatPayNotifyController {
    private static final String SUCCESS = "SUCCESS";
    private static final String FAIL = "FAIL";
    @Autowired
    WechatPayV3Properties wechatPayV3Properties;

    @PostMapping("/doCallBack")
    @Transactional(rollbackFor = Exception.class)
    public void doCallBack(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("application/json");
        response.setCharacterEncoding("utf-8");
        JSONObject resp = new JSONObject();
        //从请求头获取验签字段
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        String nonce = request.getHeader("Wechatpay-Nonce");
        String signature = request.getHeader("Wechatpay-Signature");
        String serial = request.getHeader("Wechatpay-Serial");
        log.info("请求头参数：timestamp={},nonce={},signature={},serial={}", timestamp, nonce, signature, serial);

        String requestBody = ServletUtil.getBody(request);
        log.info("微信返回请求体：{}", requestBody);
        PayResult payResult = JSONObject.parseObject(requestBody, PayResult.class);

        RequestParam requestParam = new RequestParam.Builder().serialNumber(serial).nonce(nonce).signature(signature).timestamp(timestamp).body(requestBody).build();
        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(wechatPayV3Properties.notificationConfig());

        try {
            switch (payResult.getEventType()) {
                case "TRANSACTION.SUCCESS": // 支付通知
                    // 以支付通知回调为例，验签、解密并转换成 Transaction
                    Transaction transaction = parser.parse(requestParam, Transaction.class);
                    log.info("支付成功业务参数：{}", JSONUtil.toJsonStr(transaction));
                    // 调用接口处理支付结果
                    // 通知业务服务
                    break;
                case "REFUND.SUCCESS": // 退款成功通知
                case "REFUND.ABNORMAL": // 退款异常通知
                case "REFUND.CLOSED": // 退款关闭通知
                    log.info("退款成功通知、退款异常通知、退款关闭通知");
                    RefundNotification refundNotification = parser.parse(requestParam, RefundNotification.class);
                    log.info("退款业务参数：{}", JSONUtil.toJsonStr(refundNotification));
                    switch (payResult.getEventType()) {
                        case "REFUND.SUCCESS": // 退款成功通知
                            break;
                        case "REFUND.ABNORMAL": // 退款异常通知
                            break;
                        case "REFUND.CLOSED": // 退款关闭通知
                            break;
                    }
                    break;
            }
        } catch (Exception e) {
            log.info("微信回调通知处理发生异常,{}", e);
            resp.put("code", FAIL);
            resp.put("message", e.getMessage());
            response.setStatus(500);
            response.getWriter().write(resp.toString());
            return;
        }
        //保存支付通知

        resp.put("code", SUCCESS);
        resp.put("message", "成功");
        response.setStatus(200);//不返回200，会一直推送消息
        response.getWriter().write(resp.toString());
    }
}
